package com.xiaoyyu;

import java.awt.Graphics;
import java.awt.image.BufferedImage;
import javax.swing.JFrame;
import javax.swing.JPanel;
import org.opencv.core.Mat;
import org.opencv.core.MatOfRect;
import org.opencv.core.Point;
import org.opencv.core.Rect;
import org.opencv.core.Scalar;
import org.opencv.imgproc.Imgproc;
import org.opencv.objdetect.CascadeClassifier;
import org.opencv.videoio.VideoCapture;
import org.opencv.videoio.Videoio;


/**
 * 需要连接相机，实时检测人脸.
 */
public class FaceDetection extends JPanel {

  private BufferedImage mImg;
  private static JFrame jFrame;

  //Mat转成image
  private BufferedImage matToImage(Mat mat) {
    int dataSize = (int) (mat.total() * mat.channels());
    byte[] data = new byte[dataSize];
    mat.get(0, 0, data);
    int type = mat.channels() == 1 ? BufferedImage.TYPE_BYTE_GRAY : BufferedImage.TYPE_3BYTE_BGR;

    if (type == BufferedImage.TYPE_3BYTE_BGR) {
      for (int i = 0; i < dataSize; i += 3) {
        byte blue = data[i + 0];
        data[i + 0] = data[i + 2];
        data[i + 2] = blue;
      }
    }
    //创建空的image
    BufferedImage image = new BufferedImage(mat.cols(), mat.rows(), type);
    //帧数据拷贝
    image.getRaster().setDataElements(0, 0, mat.cols(), mat.rows(), data);
    return image;
  }

  /**
   * Jpanel调用repaint的时候会自动调用该绘图方法
   */
  public void paintComponent(Graphics g) {
    if (mImg != null) {
      g.drawImage(mImg, 0, 0, mImg.getWidth(), mImg.getHeight(), this);
    }
  }

  static {
    //System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
    System.load("D:\\Program\\opencv\\build\\java\\x64\\opencv_java412.dll");
  }

  public static void creatFrame(JPanel jPanel, int width, int height) {
    jFrame = new JFrame("camera");
    jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    jFrame.setVisible(true);
    //将内容添加到JFrame
    jFrame.setSize(width, height);
    jFrame.setContentPane(jPanel);
  }

  public static void main(String[] args) throws Exception {
    //开启摄像头
    VideoCapture capture = new VideoCapture(0);
    FaceDetection jPanel = new FaceDetection();
    creatFrame(jPanel, (int) capture.get(Videoio.CAP_PROP_FRAME_WIDTH),
        (int) capture.get(Videoio.CAP_PROP_FRAME_HEIGHT));

    Mat mat = new Mat();
    while (true) {
      if (!capture.isOpened()) {
        System.out.println("camera is not open");
        System.exit(0);
      }
      capture.read(mat);
      jPanel.mImg = jPanel.matToImage(detectFace(mat));
      jPanel.repaint();
    }
  }

  /**
   * opencv实现人脸识别
   * @param mat .
   */
  public static Mat detectFace(Mat mat) throws Exception {
    // 从配置文件lbpcascade_frontalface.xml中创建一个人脸识别器，该文件位于opencv安装目录中
    CascadeClassifier faceDetector =
        new CascadeClassifier("D:\\Program\\opencv\\sources\\data\\haarcascades\\haarcascade_frontalface_alt.xml");
    // 在图片中检测人脸
    MatOfRect faceDetections = new MatOfRect();
    faceDetector.detectMultiScale(mat, faceDetections);

    Rect[] rects = faceDetections.toArray();
    for (Rect rect : rects) {
      //标出脸
      Imgproc.rectangle(mat, new Point(rect.x, rect.y), //标记框的左下点坐标
          new Point(rect.x + rect.width, rect.y + rect.height),  //标记框的右上点坐标
          new Scalar(0, 255, 0), //颜色
          2); //粗细
    }
    return mat;
  }
}